

/**********************************************************************
* FileName:        I2C.c
* Dependencies:    I2C.h
* Processor:       MC68HC908JL16
* Compiler:        CodeWarrior HC08 v5.00 or higher
*
* REVISION HISTORY: 1.0
*
* ADDITIONAL NOTES:
*   This module is processor-independent
*
*  I2C_init()           initializes the IIC driver
*  I2C_start()          issues a START condition
*  I2C_stop()           issues a STOP  conditiom
*  I2C_tx_byte( data )  transmits a byte, returns acknowledge
*  I2C_rx_byte( ack)    receives a byte, if ack=TRUE acknowledges the sender
*
* The port PTA2 is the SDA line
* The port PTA3 is the SCL line
* change it at your wish to set the properly lines for I2C communications
* the amazing of this code is you can create your own I2C port doesn't care
* if your processor is capable of I2C communications.
**********************************************************************/
#include <MC68HC908JL16.h>
#include "i2c.h"
static void I2C_tx_bit_1( void );        //transmits a logic 1
static void I2C_tx_bit_0( void );        //transmits a logic 0
static unsigned char I2C_rx_bit( void ); //receives a bit

////////////////////////////////////////////////////////////////////////////////
// CONFIGURATION SECTION
// the following code provides the methods for setting the IIC SDA (data) and
// SCL (clock) lines, and a routine to time the bus speed.
// Change them to configure for the processor/pins you are using
////////////////////////////////////////////////////////////////////////////////
#define SCL_high   {PTA_PTA3 = 1; I2C_wait();}
#define SCL_low    {PTA_PTA3 = 0; I2C_wait();}
//#define SCL_pullup_off {PTAPUE_PTAPUE3 = 0; }    // because our processor don't have a pull-up register
#define SCL_output {DDRA_DDRA3 = 1;}
#define SDA_high   {PTA_PTA2 = 1; I2C_wait();}
#define SDA_low    {PTA_PTA2 = 0; I2C_wait();}
//#define SDA_pullup {PTAPUE_PTAPUE2 = 1; }        // because our processor don't have a pull-up register
#define SDA_output {DDRA_DDRA2 = 1;}
#define SDA_input  {DDRA_DDRA2 = 0;}
#define SDA_value  (PTA_PTA2)
static void I2C_wait( void )
{
    unsigned char i;
    for ( i = 0; i < 50; i++ )
     ;;
}
////////////////////////////////////////////////////////////////////////////////
// END OF CONFIGURATION SECTION
// you should not need to change anything below this line
////////////////////////////////////////////////////////////////////////////////
/*---------------------------------------------------------------------
  Function Name: I2C_init
  Description:   initializes IIC system
  Inputs:        None
  Returns:       None
----------------------------------------------------------------------- */
void I2C_init( void ) //initializes IIC system
{
    //    SCL_pullup_off;   // because our processor don't have a pull-up register
    //    SDA_pullup;       // because our processor don't have a pull-up register
    SCL_output;
    SDA_output;
    I2C_stop();
}

/*---------------------------------------------------------------------
  Function Name: I2C_start
  Description:   issues a START condition
  Inputs:        None
  Returns:       None
----------------------------------------------------------------------- */
void I2C_start( void ) //issues a START condition
{
    SDA_output;
    SDA_high;
    SCL_high;
    SDA_low;
}

/*---------------------------------------------------------------------
  Function Name: I2C_stop
  Description:   issues a STOP condition
  Inputs:        None
  Returns:       None
----------------------------------------------------------------------- */
void I2C_stop( void ) //issues a STOP condition
{
    SDA_output;
    SDA_low;
    SCL_high;
    SDA_high;
}

/*---------------------------------------------------------------------
  Function Name: I2C_tx_byte
  Description:   transmits a byte
  Inputs:        the byte to transmit
  Returns:       returns device acknowledge
----------------------------------------------------------------------- */
unsigned char I2C_tx_byte( unsigned char B )
{
    unsigned char i;
    for ( i = 0; i < 8; i++ )
    {
        if( B & 0x80 )I2C_tx_bit_1();
        else I2C_tx_bit_0();
        B = B << 1;
    };
    i = I2C_rx_bit();
    return (i);
}

/*---------------------------------------------------------------------
  Function Name: I2C_rx_byte
  Description:   receives a byte
  Inputs:        if acknowledge = 1 generates the ACK bit
  Returns:       returns device acknowledge
----------------------------------------------------------------------- */
unsigned char I2C_rx_byte( unsigned char acknowledge )
{
    unsigned char i, retval;
    retval = 0;
    for ( i = 0; i < 8; i++ )
    {
        retval = (retval << 1);
        if( I2C_rx_bit() )retval++;
    };
    if( acknowledge )
    {
        I2C_tx_bit_0();
    }
    else
    {
        I2C_tx_bit_1();
    };
    return retval;
}


////////////////////////////////////////////////////////////////////////////////
// BIT-LEVEL, INTERNAL USE ROUTINES FOLLOW
////////////////////////////////////////////////////////////////////////////////
/*---------------------------------------------------------------------
  Function Name: I2C_tx_bit_1
  Description:   transmits a logic 1
  Inputs:        None
  Returns:       None
----------------------------------------------------------------------- */
static void I2C_tx_bit_1( void ) //transmits a logic 1
{
    SCL_low;
    SDA_output;
    SDA_high;
    SCL_high;
    SCL_low;
}

/*---------------------------------------------------------------------
  Function Name: I2C_tx_bit_0
  Description:   transmits a logic 0
  Inputs:        None
  Returns:       None
----------------------------------------------------------------------- */
static void I2C_tx_bit_0( void ) //transmits a logic 0
{
    SCL_low;
    SDA_output;
    SDA_low;
    SCL_high;
    SCL_low;
}

/*---------------------------------------------------------------------
  Function Name: I2C_rx_bit
  Description:   receives a bit
  Inputs:        None
  Returns:       returns ACK status
----------------------------------------------------------------------- */
static unsigned char I2C_rx_bit( void ) //receives a bit,returns ACK status
{
    unsigned char retval;
    SDA_input;
    SCL_low;
    SCL_high;
    retval = SDA_value;
    SCL_low;
    return retval;
}

/*---------------------------------------------------------------------
  Function Name: I2C_general_reset
  Description:   Send a General Reset command to all I2C devices
  Inputs:        None
  Returns:       None
----------------------------------------------------------------------- */
void I2C_general_reset( void ) // reset all devices into the IIC system
{
  unsigned char dummy;
    //    SCL_pullup_off;   // because our processor don't have a pull-up register
    //    SDA_pullup;       // because our processor don't have a pull-up register
    I2C_start();
    dummy = I2C_tx_byte(0x00);  // All addresses listen to me
    dummy = I2C_tx_byte(0x06);  // I'm sending the general reset command    
    I2C_stop();
}